package com.dizner.androiduploadlibrary.service;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.SystemClock;
import android.support.annotation.LayoutRes;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.widget.Toast;

import com.dizner.androiduploadlibrary.AppUtils;
import com.dizner.androiduploadlibrary.InstallApplicationTestActivity;
import com.dizner.androiduploadlibrary.R;
import com.dizner.androiduploadlibrary.javabean.ApplicationUpdateInfoBean;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Locale;

import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET;

/**
 * APP升级服务
 */
public final class UpGradeService extends Service {

    private NotificationManager mNotificationManager;
    private Notification.Builder mNotificationBuilder;
    private final int notificationId = 9112;
    private static final String CHANNEL_ID = "channel_id_upgrade"; //Android8.0 的通知通道Id
    final String CHANNEL_NAME = "channel_name_upgrade";
    private ApplicationUpdateInfoBean infoBean;
    private String apkStorePath;
    private String fileProvider;
    public static final String SP_NAME = "downLoadLog";

    private UpGradeServerStatusListener listener;
    private static Intent installApkIntent;

    private String versionName;
    private int versionCode;

    public static boolean Showed = false;

    private SharedPreferences sp;

    @LayoutRes
    private int dialogViewResId;
    private boolean isAuto;
    private boolean loading = false;
    private Intent installActivityIntent;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new DownLoadBinder();
    }

    public class DownLoadBinder extends Binder {
        public UpGradeService getService() {
            return UpGradeService.this;
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        sp = getSharedPreferences(SP_NAME, MODE_PRIVATE);
        try {
            versionName = getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
            versionCode = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        loading = false;
    }

    public void setListener(UpGradeServerStatusListener listener) {
        this.listener = listener;
    }

    @Override
    public void unbindService(ServiceConnection conn) {
        super.unbindService(conn);
        // TODO: 2018/9/27 是否可以阻挡取消绑定后，停止服务
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        apkStorePath = intent.getStringExtra("apkStorePath");

        //检查设置的路径
        if (TextUtils.isEmpty(apkStorePath)) {
            readDefaultApkPath();
        } else {
            File temp = new File(apkStorePath);
            if (!temp.canExecute() || !temp.canRead()) {
                readDefaultApkPath();
            }
        }
        dialogViewResId = intent.getIntExtra("dialogViewResId", 0);
        fileProvider = intent.getStringExtra("fileProviderName");
        isAuto = intent.getBooleanExtra("isAuto", true);
        infoBean = (ApplicationUpdateInfoBean) intent.getSerializableExtra("updateInfoBean");
        if (!Showed || !isAuto || infoBean.isMandatory()) {
            if (check()) {
                installActivityIntent = new Intent(this, InstallApplicationTestActivity.class);
                installActivityIntent.putExtra("fileProviderName", fileProvider);
                installActivityIntent.putExtra("actionType", "upgrade");
                installActivityIntent.putExtra("dialogViewResId", dialogViewResId);
                installActivityIntent.putExtra("apkStorePath", apkStorePath);
                installActivityIntent.putExtra("updateInfoBean", infoBean);
                installActivityIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
                mCallBackHandler.sendEmptyMessageDelayed(INIT_OPEN_ACTIVITY, 500); //延时跳转，等待service启动完成后在切换activity；
            } else {
                Toast.makeText(this, "已经是最新版本", Toast.LENGTH_SHORT).show();
                stopSelf();
            }
            Showed = true;
        } else {
            stopSelf();
        }

        return super.onStartCommand(intent, Service.START_FLAG_RETRY, startId);
    }


    private void readDefaultApkPath() {
        if (TextUtils.equals(Environment.MEDIA_MOUNTED,
                Environment.getExternalStorageState())) {
            File externalCacheDir = getApplicationContext().getExternalCacheDir();
            if (externalCacheDir != null) {
                apkStorePath = externalCacheDir.getPath();
            }
        } else {
            File cacheDir = getApplicationContext().getCacheDir();
            if (cacheDir != null) {
                apkStorePath = cacheDir.getPath();
            }
        }
    }

    private boolean check() {
        return versionCode < infoBean.getNewVersionCode();
    }

    public void buildNotific() {
        mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            //只在Android O之上需要渠道
            //如果这里用IMPORTANCE_NOENE就需要在系统的设置里面开启渠道，
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
                    CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH);
            channel.setDescription("用于弹出版本更新通知、显示更新进度");
            channel.enableLights(false);//闪光
            channel.setLockscreenVisibility(VISIBILITY_SECRET);//锁屏显示通知
//            channel.setLightColor(Color.RED);//指定闪光是的灯光颜色
            channel.canShowBadge();//桌面laucher消息角标
//            channel.setSound(null, null);
            channel.enableVibration(true);//是否允许震动
//            channel.getAudioAttributes();//获取系统通知响铃声音配置
            channel.getGroup();//获取通知渠道组
            channel.setBypassDnd(false);//设置可以绕过，请勿打扰模式
            channel.setVibrationPattern(new long[]{30});//震动的模式，震3次，第一次100，第二次100，第三次200毫秒
//            channel.shouldShowLights();//是否会闪光
            //通知才能正常弹出
            if (mNotificationManager != null) {
                mNotificationManager.createNotificationChannel(channel);
            }

            mNotificationBuilder = new Notification.Builder(this, CHANNEL_ID)
                    .setSmallIcon(R.drawable.ic_launcher)
                    .setContentTitle("版本更新")
                    .setContentText("下载中...");
        } else {
            mNotificationBuilder = new Notification.Builder(this)
                    .setSmallIcon(R.drawable.ic_launcher)
                    .setContentTitle("版本更新")
                    .setContentText("下载中...");
        }
        mNotificationBuilder.setAutoCancel(true);
        mNotificationBuilder.setOnlyAlertOnce(true);
    }

    public void startDownLoad() {

        buildNotific();

        installApkIntent = new Intent(getApplicationContext(), InstallApplicationTestActivity.class);
        installApkIntent.putExtra("fileProviderName", fileProvider);
        installApkIntent.putExtra("actionType", "upgrade");
        installApkIntent.putExtra("apkStorePath", apkStorePath);
        installApkIntent.putExtra("updateInfoBean", infoBean);


        new Thread() {
            @Override
            public void run() {
                InputStream input = null;
                OutputStream output = null;
                HttpURLConnection connection = null;
                File file = null;
                try {
                    URL url = new URL(infoBean.getNewApkFileUrl());
                    connection = (HttpURLConnection) url.openConnection();
                    connection.connect();
                    loading = true;
                    // expect HTTP 200 OK, so we don't mistakenly save error
                    // report
                    // instead of the file
                    if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
                        if (listener != null) {
                            listener.onDownLoadError();
                        }
                        // TODO: 2018/9/27 请求失败
                    }
                    // this will be useful to display download percentage
                    // might be -1: server did not report the length
                    int fileLength = connection.getContentLength();

                    mNotificationBuilder.setDefaults(Notification.FLAG_ONLY_ALERT_ONCE);
                    mNotificationBuilder.setProgress(100, 0, true);
                    mNotificationManager.notify(notificationId, mNotificationBuilder.build());

                    Message msg = mCallBackHandler.obtainMessage();
                    msg.what = CALL_BACK_HANDLER_CODE_ONDOWNLOADREADY;
                    msg.obj = fileLength;
                    mCallBackHandler.sendMessage(msg);

                    if (Environment.getExternalStorageState().equals(
                            Environment.MEDIA_MOUNTED)) {
                        file = new File(apkStorePath,
                                String.format("V%s-%s.apk", infoBean.getNewVersionName(), SystemClock.elapsedRealtime()));

                        if (!file.exists()) {
                            // 判断父文件夹是否存在
                            if (!file.getParentFile().exists()) {
                                file.getParentFile().mkdirs();
                            }
                        }

                    } else {
                        ToastMsgInUIThread("sd卡未挂载", Toast.LENGTH_LONG);
                    }
                    input = connection.getInputStream();


                    output = new FileOutputStream(file);
                    byte data[] = new byte[4096];
                    long total = 0;
                    int count;
                    while ((count = input.read(data)) != -1) {
                        // allow canceling with back button

                        total += count;
                        // publishing the progress....
                        // only if total length is known
                        if (fileLength > 0) {
                            long progress = total * 100 / fileLength;
                            Message msgs = mCallBackHandler.obtainMessage();
                            msgs.what = CALL_BACK_HANDLER_CODE_ONDOWNLOADING;
                            msgs.obj = progress;
                            mCallBackHandler.sendMessage(msgs);
                            mNotificationBuilder.setDefaults(Notification.FLAG_ONLY_ALERT_ONCE);
                            mNotificationBuilder.setProgress(100, (int) progress, false);
                            mNotificationBuilder.setContentText(String.format(Locale.getDefault(), "%d%%", (int) progress));
                            mNotificationManager.notify(notificationId, mNotificationBuilder.build());
                        }
                        output.write(data, 0, count);

                    }
                    // TODO: 2018/9/27 下载完成回调
                    doOnLoadFinished(file.getPath());
                } catch (Exception e) {
                    e.printStackTrace();
                    System.out.println(e.toString());
                    // TODO: 2018/9/27 下载异常回调

                } finally {
                    try {
                        if (output != null)
                            output.close();
                        if (input != null)
                            input.close();
                    } catch (IOException ignored) {
                    }
                    if (connection != null)
                        connection.disconnect();
                }
            }
        }.start();
    }

    /**
     * 在UI线程中做Toast操作
     * 如需要在子线程中操作需要手动创建Looper
     *
     * @param content
     * @param lengthShort
     */
    private void ToastMsgInUIThread(String content, int lengthShort) {
        if (TextUtils.isEmpty(content)) {
            return;
        }
        Message msg = mToastHandler.obtainMessage();
        msg.what = TOAST_HANDLER_CODE;
        msg.obj = content;
        msg.arg1 = lengthShort;
        mToastHandler.sendMessage(msg);
    }

    private void doOnLoadFinished(String path) {
        sp.edit().putString("lastDownloadPath", path).apply();
        Message msg = mCallBackHandler.obtainMessage();
        msg.what = CALL_BACK_HANDLER_CODE_ONDOWNLOADFINISHED;
        msg.obj = path;
        mCallBackHandler.sendMessage(msg);
        loading = false;
    }


    private static final int TOAST_HANDLER_CODE = 1020;

    private Handler mToastHandler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            if (msg.what == TOAST_HANDLER_CODE) {
                Toast.makeText(UpGradeService.this, msg.obj.toString(), msg.arg1).show();
            }
            return false;
        }
    });


    public void stopService(InstallApplicationTestActivity instance) {
        if (!loading) {
            stopSelf();
        }
    }

    private static final int CALL_BACK_HANDLER_CODE_ONDOWNLOADREADY = 1021;
    private static final int CALL_BACK_HANDLER_CODE_ONDOWNLOADSTART = 1022;
    private static final int CALL_BACK_HANDLER_CODE_ONDOWNLOADCANCEL = 1023;
    private static final int CALL_BACK_HANDLER_CODE_ONDOWNLOADING = 1024;
    private static final int CALL_BACK_HANDLER_CODE_ONDOWNLOADERROR = 1025;
    private static final int CALL_BACK_HANDLER_CODE_ONDOWNLOADFINISHED = 1026;
    private static final int INIT_OPEN_ACTIVITY = 1010;
    private Handler mCallBackHandler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            switch (msg.what) {
                case INIT_OPEN_ACTIVITY:
                    startActivity(installActivityIntent);
                    break;
                case CALL_BACK_HANDLER_CODE_ONDOWNLOADREADY:
                    if (listener != null) {
                        listener.onDownLoadReady((int) msg.obj);
                        listener.onDownLoadStart((int) msg.obj);
                    }
                    break;
                case CALL_BACK_HANDLER_CODE_ONDOWNLOADSTART:
                    break;
                case CALL_BACK_HANDLER_CODE_ONDOWNLOADCANCEL:
                    break;
                case CALL_BACK_HANDLER_CODE_ONDOWNLOADING:
                    long progress = (long) msg.obj;
                    if (listener != null) {
                        listener.onDownLoading(progress);
                        // TODO: 2018/9/27 进度更新
                    }
                    break;
                case CALL_BACK_HANDLER_CODE_ONDOWNLOADERROR:
                    break;
                case CALL_BACK_HANDLER_CODE_ONDOWNLOADFINISHED:
                    try {
                        if (AppUtils.getInstance(getApplicationContext()).isRunningForeground()) {
                            mNotificationManager.cancel(notificationId);
                            if (listener != null) {
                                listener.onDownLoadFinished(msg.obj.toString());
                                // TODO: 2018/9/30 activity可能已经销毁
                            }
                        } else {
                            // 下载完成，点击安装
                            PendingIntent pendingIntent = PendingIntent.getActivity(UpGradeService.this, 0, installApkIntent, PendingIntent.FLAG_UPDATE_CURRENT);
                            mNotificationBuilder.setAutoCancel(true);
                            mNotificationBuilder.setContentText("下载成功，点击安装");
                            mNotificationBuilder.setContentIntent(pendingIntent);
                            mNotificationManager.notify(notificationId, mNotificationBuilder.build());
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        startActivity(installApkIntent);
                    }
                    break;
            }
            return false;
        }
    });


    public interface UpGradeServerStatusListener {
        void onDownLoadReady(float totalSize);

        void onDownLoadStart(float totalSize);

        void onDownLoadCancel();

        void onDownLoading(float progress);

        void onDownLoadError();

        void onDownLoadFinished(String filePath);
    }

}
